package com.huopaolan.yohuoshop.Mvc.Model;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.hardware.SensorManager;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

public class MyScrollView extends View {
    public static final String TAG = "MyScrollView";
    Paint paint, zPaint;
    //数据源
    List<String> dataList;
    //字的大小
    int textSize = 50;
    //item之间的间距
    int interval = 30;
    int lineSize = 30;
    //偏差
    float offSet = 0;
    //view的宽高
    int width, height;
    //总高度
    int sumHeight;
    float centerY;
    float linePad = 20;
    float now;
    float move;
    private VelocityTracker mVelocityTracker;
    /**
     * 自动回滚到中间的速度
     */
    public static final float SPEED = 5;
    //甩手和归为
    private Timer timer;
    private MyTimerTask mTask;
    //归位，为了一定选中某个item
    private Timer flingtimer;
    private MyTimerTask flingmTask;
    @SuppressLint("HandlerLeak")
    Handler updateHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (Math.abs(surplus) < SPEED) {
                surplus = 0;
                if (mTask != null) {
                    mTask.cancel();
                    mTask = null;
                }
            } else if (surplus != 0) {
                offSet = surplus / Math.abs(surplus) * SPEED + offSet;
                surplus = (int) (surplus - surplus / Math.abs(surplus) * SPEED);
                invalidate();
            }
        }
    };
    //fling实现
    @SuppressLint("HandlerLeak")
    Handler flingHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (Math.abs(yVelocity) < mMinimumFlingVelocity) {
                yVelocity = 0;
                if (flingmTask != null) {
                    flingmTask.cancel();
                    flingmTask = null;
                }
                guiwei();
            } else if (yVelocity != 0) {
                offSet = (float) (offSet + yVelocity * 0.01);
                double d = distance - Math.abs(yVelocity) * 0.01;
                yVelocity = getVelocityByDistance(distance) * yVelocity / Math.abs(yVelocity);
                distance = d;
                invalidate();
            }
        }
    };

    public MyScrollView(Context context) {
        super(context);
        init();
    }

    public MyScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public void init() {
        paint = new Paint();
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStyle(Paint.Style.FILL);
        paint.setTextAlign(Paint.Align.CENTER);
        paint.setColor(Color.BLACK);
        paint.setTextSize(textSize);
        zPaint = new Paint();
        zPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        zPaint.setStyle(Paint.Style.FILL);
        zPaint.setTextAlign(Paint.Align.CENTER);
        zPaint.setTextSize(textSize);
        dataList = new ArrayList<>();
        sumHeight = interval * (dataList.size() + 1) + textSize * dataList.size();
        centerY = (float) (interval + textSize * 0.5);
        timer = new Timer();
        flingtimer = new Timer();
        final ViewConfiguration viewConfiguration = ViewConfiguration.get(getContext());
        mMinimumFlingVelocity = viewConfiguration.getScaledMinimumFlingVelocity();
        mMaximumFlingVelocity = viewConfiguration.getScaledMaximumFlingVelocity();
        minFLingDistance = getSplineFlingDistance(mMinimumFlingVelocity);
    }

    double minFLingDistance;

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //invalidate();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        width = w;
        height = h;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (dataList == null || dataList.size() == 0) {
            return;
        }
        canvas.clipRect(0, 0, 300, (int) (3.5 * interval + textSize * 3));
        //滑动下限
        if (offSet <= -sumHeight + textSize * 2 + interval * 3) {
            offSet = -sumHeight + textSize * 2 + interval * 3;
        }
        //滑动上限
        if (offSet > textSize + interval) {
            offSet = textSize + interval;
        }
        float start = offSet;
        for (String s : dataList) {
            Rect rect = new Rect();
            paint.getTextBounds(s, 0, s.length(), rect);
            // 获取到的是实际文字宽度
            int textWidth = rect.width();
            start = start + interval;
            canvas.drawText(s, (width - textWidth) / 1.5f, start + textSize, paint);
            start = start + textSize;

        }

        canvas.drawLine(linePad,
                (float) (interval * 1.5 + textSize), width - linePad, (float) (interval * 1.5 + textSize), zPaint);
        canvas.drawLine(linePad, (float) (interval * 2.5 + textSize * 2),
                width - linePad, (float) (interval * 2.5 + textSize * 2), zPaint);
    }

    int surplus;
    private int mMaximumFlingVelocity;
    private int mMinimumFlingVelocity;
    int yVelocity;
    int duration;
    double distance;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                now = event.getY();
                initOrResetVelocityTracker();
                break;
            case MotionEvent.ACTION_MOVE:
                move = event.getY() - now;
                now = event.getY();
                offSet = offSet + move;
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                final VelocityTracker velocityTracker = mVelocityTracker;
                velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
                if (Math.abs(velocityTracker.getYVelocity()) > mMinimumFlingVelocity) {
                    yVelocity = (int) velocityTracker.getYVelocity();
                    duration = getSplineFlingDuration(yVelocity);
                    distance = getSplineFlingDistance(yVelocity);
                    Log.v(TAG, "初速度：" + yVelocity + "移动距离：" + distance + "移动时间：" + duration);
                    if (flingmTask != null) {
                        flingmTask.cancel();
                        flingmTask = null;
                    }
                    flingmTask = new MyTimerTask(flingHandler);
                    flingtimer.schedule(flingmTask, 0, 10);
                } else {
                    guiwei();
                }
/*                if(offSet<0){
                    surplus= (int)(-offSet)%(int)(textSize+interval);
                    if(surplus<(textSize+interval)/2){
                    }else {
                        surplus=-(textSize+interval-surplus);
                    }
                }else {
                    surplus= (int)(offSet)%(int)(textSize+interval);
                    if(surplus<(textSize+interval)/2){
                        surplus=-surplus;
                    }else {
                        surplus=textSize+interval-surplus;
                    }
                }
                if (mTask != null)
                {
                    mTask.cancel();
                    mTask = null;
                }
                mTask = new MyTimerTask(updateHandler);
                timer.schedule(mTask, 0, 10);*/
                invalidate();
                break;
        }
        if (mVelocityTracker != null) {
            mVelocityTracker.addMovement(event);
        }
        return true;
    }

    class MyTimerTask extends TimerTask {
        Handler handler;

        public MyTimerTask(Handler handler) {
            this.handler = handler;
        }

        @Override
        public void run() {
            handler.sendMessage(handler.obtainMessage());
        }
    }

    private void initOrResetVelocityTracker() {
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        } else {
            mVelocityTracker.clear();
        }
    }

    private void resetVelocityTracker() {
        if (mVelocityTracker != null) {
            mVelocityTracker.clear();
        }
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        final float ppi = getContext().getResources().getDisplayMetrics().density * 160.0f;
        mPhysicalCoeff = SensorManager.GRAVITY_EARTH // g (m/s^2)
                * 39.37f // inch/meter
                * ppi
                * 0.84f; // look and feel tuning
    }

    private static final float INFLEXION = 0.35f; // Tension lines cross at (INFLEXION, 1)
    // A context-specific coefficient adjusted to physical values.
    private float mPhysicalCoeff;
    private static float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9));
    // Fling friction
    private float mFlingFriction = ViewConfiguration.getScrollFriction();

    //获取滑动的时间
    private int getSplineFlingDuration(int velocit) {
        final double l = getSplineDeceleration(velocit);
        final double decelMinusOne = DECELERATION_RATE - 1.0;
        return (int) (1000.0 * Math.exp(l / decelMinusOne));
    }

    private double getSplineDeceleration(float velocity) {
        return Math.log(INFLEXION * Math.abs(velocity) / (mFlingFriction * mPhysicalCoeff));
    }

    //通过初始速度获取最终滑动距离
    private double getSplineFlingDistance(int velocity) {
        final double l = getSplineDeceleration(velocity);
        final double decelMinusOne = DECELERATION_RATE - 1.0;
        return mFlingFriction * mPhysicalCoeff * Math.exp(DECELERATION_RATE / decelMinusOne * l);
    }

    //通过需要滑动的距离获取初始速度
    public int getVelocityByDistance(double distance) {
        final double l = getSplineDecelerationByDistance(distance);
        int velocity = (int) (Math.exp(l) * mFlingFriction * mPhysicalCoeff / INFLEXION);
        return Math.abs(velocity);
    }

    private double getSplineDecelerationByDistance(double distance) {
        final double decelMinusOne = DECELERATION_RATE - 1.0;
        return decelMinusOne * (Math.log(distance / (mFlingFriction * mPhysicalCoeff))) / DECELERATION_RATE;
    }

    int currentItem;

    public void guiwei() {
        if (offSet < 0) {
            surplus = (int) (-offSet) % (int) (textSize + interval);
            if (surplus < (textSize + interval) / 2) {

            } else {
                surplus = -(textSize + interval - surplus);
            }
        } else {
            surplus = (int) (offSet) % (int) (textSize + interval);
            if (surplus < (textSize + interval) / 2) {
                surplus = -surplus;
            } else {
                surplus = textSize + interval - surplus;
            }
        }
        currentItem = -(int) ((surplus + offSet) / (textSize + interval)) + 1;
        Log.v(TAG, "currentItem: " + currentItem);
        if (selectItemListener != null) {
            selectItemListener.selectItem(currentItem);
        }

        if (mTask != null) {
            mTask.cancel();
            mTask = null;
        }
        mTask = new MyTimerTask(updateHandler);
        timer.schedule(mTask, 0, 10);
    }

    public interface SelectItemListener {
        public void selectItem(int index);
    }

    private SelectItemListener selectItemListener;

    public void setSelectItemListener(SelectItemListener selectItemListener) {
        this.selectItemListener = selectItemListener;
    }

    public void setDataList(List<String> dataList) {
        this.dataList = dataList;
        sumHeight = interval * (dataList.size() + 1) + textSize * dataList.size();
        invalidate();
    }
}
